﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
using System.Configuration;
using TireService.Data;
using System.Web.Caching;
using System.Diagnostics;
using System.Net;
using System.Collections;
using System.Security.Principal;

namespace TireService.Web
{
    public class Global : System.Web.HttpApplication
    {
        private string DummyPageUrl = ConfigurationManager.AppSettings["ScheduledJobsDummyPage"].ToString();
        //private const string DummyPageUrl = "http://intranet.mobilhjulskift.dk/Interfaces/ScheduledJobs/TestCacheTimeout.aspx"; //ConfigurationManager.AppSettings["ScheduledJobsDummyPage"].ToString();
        private const string DummyCacheItemKey = "MBHCacheItem";

        public static ArrayList _JobQueue = new ArrayList();

        // Code for adding job to global que from a random ASPX page - example - job will run after 4 minutes
        //Job newJob = new Job( "A job queued at: " + DateTime.Now, 
        //              DateTime.Now.AddMinutes(4) );
        //lock( Global._JobQueue )
        //{
        //    Global._JobQueue.Add( newJob );
        //}

        void Application_Start(object sender, EventArgs e)
        {
            // Code that runs on application startup

            // If the dummy page is hit, then it means we want to add another item

            // in cache
            if (HttpContext.Current.Request.Url.ToString() == DummyPageUrl)
            {
                // Add the item in cache and when succesful, do the work.
                RegisterCacheEntry();
            }

            
            
            
            
            
            
            //// NOTE - 10-08-2013: Old scheduler below here

            //// Dynamically create new timer
            //System.Timers.Timer timScheduledTask = new System.Timers.Timer();

            //// Timer interval is set in miliseconds,
            //// In this case, we'll run a task every day
            //timScheduledTask.Interval = 24 * 60 * 60 * 1000; //(24 hours x 60min x 60sek x 1000ms)

            //timScheduledTask.Enabled = true;

            //// Add handler for Elapsed event
            //timScheduledTask.Elapsed +=
            //new System.Timers.ElapsedEventHandler(timScheduledTask_Elapsed);
        }

        /// <summary>
        /// Register a cache entry which expires in 1 minute and gives us a callback.
        /// </summary>
        /// <returns></returns>
        private void RegisterCacheEntry()
        {
            //if (HttpRuntime.Cache.Get(DummyCacheItemKey) != null) return;

            //HttpRuntime.Cache.Add(DummyCacheItemKey, "Test", null,
            //    DateTime.MaxValue, TimeSpan.FromSeconds(1),
            //    CacheItemPriority.Normal,
            //    new CacheItemRemovedCallback(CacheItemRemovedCallback));


            // Prevent duplicate key addition
            if (null != HttpContext.Current.Cache[DummyCacheItemKey]) return;

            HttpContext.Current.Cache.Add(DummyCacheItemKey, "Test", null, DateTime.MaxValue,
                TimeSpan.FromMinutes(1), CacheItemPriority.NotRemovable,
                new CacheItemRemovedCallback(CacheItemRemovedCallback));
        }

        /// <summary>
        /// Callback method which gets invoked whenever the cache entry expires.
        /// We can do our "service" works here.
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="reason"></param>
        public void CacheItemRemovedCallback(string key, object value, CacheItemRemovedReason reason)
        {
            Debug.WriteLine("Cache item callback: " + DateTime.Now.ToString());

            // Do the service works
            DoWork();

            // We need to register another cache item which will expire again in one
            // minute. However, as this callback occurs without any HttpContext, we do not
            // have access to HttpContext and thus cannot access the Cache object. The
            // only way we can access HttpContext is when a request is being processed which
            // means a webpage is hit. So, we need to simulate a web page hit and then 
            // add the cache item.
            HitPage();
        }

        /// <summary>
        /// Hits a local webpage in order to add another expiring item in cache
        /// </summary>
        private void HitPage()
        {
            WebClient client = new WebClient();
            client.DownloadData(DummyPageUrl);
        }

        /// <summary>
        /// Asynchronously do the 'service' works
        /// </summary>
        private void DoWork()
        {
            Debug.WriteLine("Begin DoWork...");
            Debug.WriteLine("Running as: " + WindowsIdentity.GetCurrent().Name);

            //DoSomeFileWritingStuff();
            //DoSomeDatabaseOperation();
            //DoSomeEmailSendStuff();
            //DoSomeMSMQStuff();
            ExecuteQueuedJobs();

            Debug.WriteLine("End DoWork...");
        }

        /// <summary>
        /// Execute jobs that are queued for execution at a specific time
        /// </summary>
        private void ExecuteQueuedJobs()
        {
            TireServiceDB db = new TireServiceDB();

            // Get scheduled jobs that has not been run and is overdue/pending
            List<ScheduledJobQueue> jobs = db.GetScheduledJobsOverduePending(DateTime.Now);

            if (jobs.Count > 0)
            {
                // Execute the jobs that are overdue
                foreach (ScheduledJobQueue job in jobs)
                {
                    // Execute job
                    ScheduledJobs scheduledjobs = new ScheduledJobs();
                    scheduledjobs.ExecuteJob(db, job);
                }    
            }
            
            //// NOTE: Jobqueue outcommented (10-08-2013)

            //ArrayList jobs = new ArrayList();

            //// Collect which jobs are overdue
            //foreach (Job job in _JobQueue)
            //{
            //    if (job.ScheduledExecutionTime <= DateTime.Now)
            //        jobs.Add(job);
            //}

            //// Execute the jobs that are overdue
            //foreach (Job job in jobs)
            //{
            //    lock (_JobQueue)
            //    {
            //        _JobQueue.Remove(job);
            //    }

            //    job.Execute();
            //}
        }

        //void timScheduledTask_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        //{
        //    // Execute some task
        //    ServiceTask();
        //}

        //void ServiceTask()
        //{
        //    // Here is the code we need to execute periodically
        //    try
        //    {
        //        string emailaddress = Convert.ToString(ConfigurationManager.AppSettings["SystemEmailAddress"]);
        //        bool test = Convert.ToBoolean(Convert.ToByte(ConfigurationManager.AppSettings["TestEnvironmentOn"]));
        //        string message = String.Format("Det virker sku:<br><br>Afsendt: {0} kl. {1}", DateTime.Now.ToShortDateString(), DateTime.Now.ToShortTimeString());

        //        Shared email = new Shared();
        //        email.SendEmail(emailaddress, emailaddress, message, "Test af schedule task - det virker :-)", true, test, null, null, null);
        //    }
        //    catch (Exception ex)
        //    {
        //        // Nothing
        //    }
        //}

        protected void Application_BeginRequest(Object sender, EventArgs e)
        {
            // If the dummy page is hit, then it means we want to add another item
            // in cache
            if (HttpContext.Current.Request.Url.ToString() == DummyPageUrl)
            {
                // Add the item in cache and when succesful, do the work.
                RegisterCacheEntry();
            }
        }

        void Application_End(object sender, EventArgs e)
        {
            //  Code that runs on application shutdown

        }

        void Application_Error(object sender, EventArgs e)
        {
            // Code that runs when an unhandled error occurs

            Debug.WriteLine(Server.GetLastError());
        }

        void Session_Start(object sender, EventArgs e)
        {
            // Code that runs when a new session is started

        }

        void Session_End(object sender, EventArgs e)
        {
            // Code that runs when a session ends. 
            // Note: The Session_End event is raised only when the sessionstate mode
            // is set to InProc in the Web.config file. If session mode is set to StateServer 
            // or SQLServer, the event is not raised.

        }

    }
}
